package br.com.gr.jcash.dao;

import br.com.gr.jcash.dmp.Categoria;
import br.com.gr.jcash.dmp.Conta;
import br.com.gr.jcash.dmp.Movimento;
import br.com.gr.jcash.dmp.TipoCategoria;
import br.com.gr.jcash.dmp.Usuario;
import br.com.gr.jcash.exception.JCashException;
import br.com.gr.jcash.utils.Filtro;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Join;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

@Stateless
public class MovimentoDAO extends AbstractDAO<Movimento, Long> {

    @PersistenceContext(unitName = "jcash-PU")
    private EntityManager em;

    @Override
    protected EntityManager getEntityManager() {
        return em;
    }

    public MovimentoDAO() {
        super(Movimento.class);
    }

    @Override
    public List<Movimento> buscarTodos(Usuario usuario) throws JCashException {
        return buscarTodos("Movimento.buscarTodos", usuario);
    }

    @Override
    public List<Movimento> buscarPorFaixa(Usuario usuario, int[] faixa) throws JCashException {
        return buscarPorFaixa("Movimento.buscarTodos", faixa, usuario);
    }

    @Override
    public Long count(Usuario usuario) throws JCashException {
        return count("Movimento.count", usuario);
    }

    public List<Movimento> buscarTodosFiltro(Usuario usuario, Filtro filtro) throws JCashException {
        CriteriaBuilder cb = getEntityManager().getCriteriaBuilder();
        CriteriaQuery cq = cb.createQuery();
        Root e = cq.from(Movimento.class);
        Join<Movimento, Conta> ctaDestino = e.join("ctaDestino");
        Join<Movimento, Conta> ctaOrigem = e.join("ctaOrigem");
        Join<Conta, Categoria> catDestino = ctaDestino.join("categoria");
        Join<Conta, Categoria> catOrigem = ctaOrigem.join("categoria");
        
        List<Predicate> condicoes = new ArrayList<>();

        condicoes.add(cb.equal(e.get("usuario"), usuario));
        condicoes.add(cb.between(e.get("mvtData"), filtro.getDataInicial(), filtro.getDataFinal()));

        if (null != filtro.getTipoCategoria()) {
            if (filtro.getTipoCategoria().equals(TipoCategoria.D)) {
                condicoes.add(cb.equal(catDestino.get("catTipo"), filtro.getTipoCategoria()));
            }
            if (filtro.getTipoCategoria().equals(TipoCategoria.R)) {
                condicoes.add(cb.equal(catOrigem.get("catTipo"), filtro.getTipoCategoria()));
            }
        }

        if (null != filtro.getCategoria()) {
            if (filtro.getCategoria().getCatTipo().equals(TipoCategoria.D)) {
                condicoes.add(cb.equal(ctaDestino.get("categoria"), filtro.getCategoria()));
            }

            if (filtro.getCategoria().getCatTipo().equals(TipoCategoria.R)) {
                condicoes.add(cb.equal(ctaOrigem.get("ctaOrigem.categoria"), filtro.getCategoria()));
            }
        }

        if (null != filtro.getConta()) {
            condicoes.add(cb.or(cb.equal(e.get("ctaOrigem"), filtro.getConta()), cb.equal(e.get("ctaDestino"), filtro.getConta())));
        }

        if(!condicoes.isEmpty()){
			cq.where((Predicate[]) condicoes.toArray(new Predicate[0]));
		}
        
        cq.orderBy(cb.asc(e.get("mvtData")));
       
        TypedQuery tp = getEntityManager().createQuery(cq);
        List<Movimento> lista = tp.getResultList();
        return lista;
    }

    public Long countPorConta(Usuario usuario, Conta conta) throws JCashException {
        return count("Movimento.countPorConta", usuario, conta, conta);
    }

    public Long countPorContaDataAnterior(Usuario usuario, Conta conta, Date data) throws JCashException {
        return count("Movimento.countPorContaDataAnterior", usuario, conta, conta, data);
    }

    public List<String> getHistorico() throws JCashException {
        Query query = getEntityManager().createNativeQuery("select distinct m.mvt_historico from movimento m order by m.mvt_historico");
        return query.getResultList();
    }
}
